package com.yang.crawler.pdf;


import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import com.yang.crawler.common.BusinessException;
import com.yang.crawler.common.ResultCode;
import com.yang.crawler.file.IFileUploader;
import com.yang.crawler.html.dto.HtmlBlockDTO;
import com.yang.crawler.html.enums.HtmlTagEnum;
import com.yang.crawler.pdf.config.PdfPropertyContext;
import com.yang.crawler.pdf.request.Html2PdfBuildRequest;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

@Component
public class Html2PdfBuilder {
    @Resource
    private IFileUploader localFileUploader;

    @Resource
    private PdfPropertyContext pdfPropertyContext;

    public byte[] mergePdf(List<byte[]> pdfList) {
        try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
            Document document = new Document(PageSize.A4);
            PdfCopy copy = new PdfCopy(document, os);
            // 打开文档
            document.open();

            for (byte[] bytes : pdfList) {
                PdfReader reader = new PdfReader(bytes);
                // 获取页数
                int numberOfPages = reader.getNumberOfPages();
                // 从第一页开始
                for (int i = 1; i <= numberOfPages; i++) {
                    // 新建文档页
                    document.newPage();
                    // 复制操作
                    PdfImportedPage page = copy.getImportedPage(reader, i);
                    copy.addPage(page);
                }
            }
            document.close();
            return os.toByteArray();
        } catch (Exception e) {
            throw new BusinessException(ResultCode.HTML_2_PDF_ERROR);
        }
    }

    public byte[] html2Pdf(Html2PdfBuildRequest html2PdfBuildRequest) {
        byte[] bytes = null;
        String title = html2PdfBuildRequest.getTitle();
        List<HtmlBlockDTO> htmlBlockDTOList = html2PdfBuildRequest.getHtmlBlockDTOList();

        Document document = new Document(PageSize.A4);
        document.addTitle(title);
        try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
            PdfWriter writer = PdfWriter.getInstance(document, byteArrayOutputStream);
            writer.setInitialLeading(30);
            document.open();
            // 设置每行的间距
            buildPdfTitle(document, title);
            buildPdfContent(document, htmlBlockDTOList);
            document.close();
            writer.close();
            bytes = byteArrayOutputStream.toByteArray();
        } catch (IOException | DocumentException e) {
            e.printStackTrace();
            throw new BusinessException(ResultCode.HTML_2_PDF_ERROR);
        }
        return bytes;
    }

    private void buildPdfContent(Document document, List<HtmlBlockDTO> htmlBlockDTOList) throws DocumentException, IOException {
        BaseFont fangSim = getBaseFont();
        Font paragraphFont = new Font(fangSim, pdfPropertyContext.getParagraphFontSize());
        for (HtmlBlockDTO htmlBlockDTO : htmlBlockDTOList) {
            HtmlTagEnum htmlTag = htmlBlockDTO.getHtmlTag();
            switch (htmlTag) {
                case H:
                case H1:
                case H2:
                case H3:
                case H4:
                case H5:
                case H6:
                    buildContentOfH(document, htmlBlockDTO, paragraphFont);
                    break;
                case PARAGRAPH:
                    buildContentOfParagraph(document, htmlBlockDTO, paragraphFont);
                    break;
                case IMG:
                    buildContentOfImg(document, htmlBlockDTO, paragraphFont);
                    break;
            }
        }
    }

    private void buildContentOfImg(Document document, HtmlBlockDTO htmlBlockDTO, Font paragraphFont) throws IOException, DocumentException {
        InputStream inputStream = localFileUploader.downloadFile(htmlBlockDTO.getContent());
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[8 * 1024];
        int read = -1;
        while ((read = inputStream.read(buffer)) != -1) {
            baos.write(buffer, 0, read);
        }
        inputStream.close();
        Image image = Image.getInstance(baos.toByteArray());
        float pdfWidth = PageSize.A4.getWidth();
        float imageWidth = image.getWidth();
        float scale = (pdfWidth - 20) / imageWidth;
        imageWidth = imageWidth * scale;
        float imageHeight = image.getHeight() * scale;
        image.scaleAbsolute(imageWidth, imageHeight);
        document.add(image);
    }

    private void buildContentOfParagraph(Document document, HtmlBlockDTO htmlBlockDTO, Font paragraphFont) throws DocumentException {
        document.add(new Paragraph(htmlBlockDTO.getContent(), paragraphFont));
    }

    private void buildContentOfH(Document document, HtmlBlockDTO htmlBlockDTO, Font paragraphFont) throws DocumentException {
        int level = 1;
        String tag = htmlBlockDTO.getHtmlTag().getTagName();
        if (tag.length() == 2) {
            level = Integer.valueOf(tag.substring(1));
        }
        float size = paragraphFont.getSize() + (7 - level) * pdfPropertyContext.getHScale();
        document.add(new Paragraph(htmlBlockDTO.getContent(), new Font(paragraphFont.getBaseFont(), size, Font.BOLD)));
    }

    private void buildPdfTitle(Document document, String title) throws DocumentException {
        BaseFont fangSim = getBaseFont();
        Font titleFont = new Font(fangSim, pdfPropertyContext.getTitleFontSize(), Font.BOLD);
        document.add(new Paragraph(title, titleFont));
    }

    public BaseFont getBaseFont() {
        try {
            String path = this.getClass().getClassLoader().getResource("fonts/simfang.ttf").getPath();
            BaseFont fangSim = BaseFont.createFont(path, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            return fangSim;
        } catch (IOException | DocumentException e) {
            throw new BusinessException(ResultCode.FONT_BUILD_ERROR);
        }
    }
}
